package com.ruoyi.oss.service.impl;

import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.oss.entity.UploadResult;
import com.ruoyi.oss.enumd.OssEnumd;
import com.ruoyi.oss.exception.OssException;
import com.ruoyi.oss.properties.OSSProperties;
import com.ruoyi.oss.service.abstractd.AbstractOssStrategy;
import io.minio.*;
import io.minio.errors.*;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import sun.awt.geom.AreaOp;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author 最爱喝兽奶
 * @create 2022/6/13
 **/
public class MinioOssStrategy extends AbstractOssStrategy {

    private MinioClient minioClient;

    private ThreadPoolTaskExecutor threadPoolTaskExecutor = SpringUtils.getBean("threadPoolTaskExecutor");

    @Override
    public void init(OSSProperties ossProperties) {
        this.ossProperties = ossProperties;
        try {
            this.minioClient = MinioClient.builder()
                    .endpoint(ossProperties.getEndpoint())
                    .credentials(ossProperties.getAccessKey(), ossProperties.getSecretKey())
                    .build();
            createBucket();
        } catch (Exception e) {
            throw new OssException("Minio存储配置错误，请检查配置");
        }

    }

    @Override
    public void createBucket() {
        String bucketName = this.ossProperties.getBucketName();
        try {
            // 先判断桶是否存在，如果不存在就创建
            boolean exists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
            if (!exists) {
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public String getServiceType() {
        // 获取当前文件服务器的类型
        return OssEnumd.MINIO.getValue();
    }

    @Override
    public UploadResult upload(byte[] data, String path, String contentType) {
        return upload(new ByteArrayInputStream(data), path, contentType);
    }

    @Override
    public synchronized UploadResult upload(InputStream is, String path, String contentType) {
        threadPoolTaskExecutor.execute(new Runnable() {
            @SneakyThrows
            @Override
            public void run() {
                try {
                    minioClient.putObject(PutObjectArgs.builder()
                            .bucket(ossProperties.getBucketName())
                            .object(path)
//                    .contentType(MediaType.APPLICATION_OCTET_STREAM_VALUE)
                            .contentType(MediaType.IMAGE_PNG_VALUE)
                            .stream(is, is.available(), -1)
                            .build());
                } catch (Exception e) {
                    throw new OssException("上传文件失败，请核对Minio配置信息:[" + e.getMessage() + "]");
                }
            }
        });
        return new UploadResult().setUrl(getEndpointLink() + "/" + path).setFilename(path);
    }

    @Override
    public UploadResult uploadSuffix(byte[] data, String suffix, String contentType) {
        return upload(data, getPath(ossProperties.getPrefix(), suffix), contentType);
    }

    @Override
    public UploadResult uploadSuffix(InputStream is, String suffix, String contentType) {
        return upload(is, getPath(ossProperties.getPrefix(), suffix), contentType);
    }

    @Override
    public void delete(String path) {
        // 获取minio服务器的路径(如果传入的是完整的url路径就删除前缀，只剩下minio服务器的路径)
        path = path.replaceAll(getEndpointLink(), "");
        try {
            minioClient.removeObject(RemoveObjectArgs.builder()
                    .bucket(ossProperties.getBucketName())
                    .object(path)
                    .build());
        } catch (Exception e) {
            throw new OssException(e.getMessage());
        }

    }
}
